package com.lcc.lynx.common.utils;

import java.io.*;
import java.util.ArrayList;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

/**
 * 文件，对象写文件，properties操作工具
 * @author 58347
 */
	//记得用File的父子路径
public class FileUtils {
	//private static String configPath="src\\config.properties";
	
	/**
	 * 1:目录,目录，进行文件夹copy
	 * 2:文件,目录，执行文件copy到目录
	 * @param file1
	 * @param file2
	 */
	//整合工具，根据传入文件还是目录自动匹配
	public static void copy(File file1,File file2) {
		//都是目录进行文件夹copy
		if(file1.isDirectory()&&file2.isDirectory())
			copy_dir(file1, file2);
		//文件到目录，执行文件copy到目录
		else if(file1.isFile()&&file2.isDirectory())
			copy_file(file1, file2);
		else
			throw new RuntimeException("文件格式错误！");
	}
	public static void copy(String path1,String path2) {
		copy(new File(path1), new File(path2));
	}
	/**
	 * 文件批量重命名
	 * @param dir		那个文件夹下
	 * @param newName	新名字
	 * 						name-$.txt=name-1.txt
	 * 						name($).doc=name(2).doc
	 * @param end		以什么结尾的文件
	 * 						all全部
	 */
	public static boolean renames(File dir,String newName, String end) {
		if(dir==null)
			throw new RuntimeException("文件为null");
		if(!dir.exists())
			throw new RuntimeException("文件不存在");
		if(dir.isFile())
			throw new RuntimeException("格式错误，应为文件夹");
		
		File[] fl = dir.listFiles(new FileFilter() {
			@Override
			public boolean accept(File f) {
				if(f.isDirectory())
					return false;
				if(end==null || end.equals("all"))
					return true;
				return f.getName().endsWith(end);
			}
		});
		int len = fl.length;
		if(len==0) return true;
		boolean b=true;
		for (int i = 0; i < fl.length; i++) 
			if(!fl[i].renameTo(new File(fl[i].getParent(),newName.replace("$", i+1+"")))) 
				b=false;
		return b;
	}
	public static boolean renames(String dir,String newName) {
		return renames(new File(dir),newName, null);
	}
	/**
	 * 从文件读出properties
	 * @param file	properties 文件路径
	 * @return		properties 
	 */
	public static Properties readeProperties(File file) {
		if(file==null)
			throw new RuntimeException("文件为null");
		if(!file.exists())
			throw new RuntimeException("文件不存在");
		Properties pro = new Properties();
		try(
			Reader r = new FileReader(file.getPath())){
			pro.load(r);
		} catch (Exception e) {e.printStackTrace();}
        return pro;
	}
	public static Properties readeProperties(String path){
		return readeProperties(new File(path));
	}
	/**
	 * 把properties存入文件
	 * @param file	properties 写入文件路径
	 * @param pro	要写入文件的Properties集合
	 */
	public static void writeProperties(File file, Properties pro) {
		if(file == null) 
			throw new RuntimeException("文件为null");
		try(
			Writer w = new FileWriter(file.getPath());){
			pro.store(w," configuration files ");
		}catch(Exception e) {e.printStackTrace();}
	}
	public static void writeProperties(String path,Properties pro) {
		writeProperties(new File(path), pro);
	}
	/**
	 * 把 Map写入 properties
	 * @param file	map 以 properties 写入文件路径
	 * @param map	要写入文件的map集合
	 */
	public static void writeMap(File file, Map<String, String> map) {
		if(file == null) 
			throw new RuntimeException("文件为null");
		Properties pro = new Properties();
		Set<String> set = map.keySet();
		for (String str : set) 
			pro.setProperty(str, map.get(str));
		try(
			Writer w = new FileWriter(file.getPath());){
			pro.store(w," map to properties");
		}catch(Exception e) {e.printStackTrace();}
	}
	/**
	 * 如果文件存在则命名为副本
	 * @param file1
	 * @param file2
	 * @return
	 */
	private static File rename(File file1,File file2) {
		int k=1;
		File file3 = new File(file2.getPath(),file1.getName());
		if(file1.isDirectory()&&file2.isDirectory()) {
			while(file3.exists()) //先减去原来的副本，添加新副本+1
				file3 = new File(file3.getParent(),file3.getName().replace("-副本"+(k-1), "")+"-副本"+k++);
			file3.mkdirs();
		}
		else if(file1.isFile()&&file2.isDirectory()) 
			while(file3.exists()) {
				String suffix = file3.getName().substring(file3.getName().lastIndexOf("."));
				String name = file3.getName().replace(suffix, "").replace("-副本"+(k-1), "")+"-副本"+ k++;
				file3 = new File(file3.getParent(),name+suffix);
			}
		return file3;
	}

	/**
	 * 从文件中读取全部对象
	 * @param <T>	以生命类型读读
	 * @param file	要读取对象的文件
	 * @param c		对象类型
	 * @return		读取到的对象列表
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public static <T> T[] readesObj(File file, Class<T> c) throws Exception{
		if(file==null)
			throw new RuntimeException("文件为null");
		if(!file.exists())
			throw new RuntimeException("文件不存在");
		InputStream in = new FileInputStream(file);
		ArrayList<T> list = new ArrayList<>();
		while(true) {
			try(
				MyObjInStream myois = new MyObjInStream(in);){
				list.add((T) myois.readObject());
			} catch(EOFException e) {
				break;
			} catch(Exception e2) {
				throw new RuntimeException("对象类型不匹配");
			}
		}
		return (T[]) list.toArray();
	}
	/**
	 * 读取一个对象
	 * @param <T>
	 * @param file
	 * @param c
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public static <T> T readeObj(File file, Class<T> c){
		if(file==null)
			throw new RuntimeException("文件为null");
		if(!file.exists())
			throw new RuntimeException("文件不存在");
		try(
			InputStream in = new FileInputStream(file);
			MyObjInStream myois = new MyObjInStream(in);){
			
			return (T) myois.readObject();
		} catch (Exception e) {
			e.printStackTrace();
		return null;
		} 
	}
	/**
	 * 把一组对象写入文件
	 * @param <T>	对象类型
	 * @param arr	对象数组
	 * @param file	写入的文件
	 * @throws IOException
	 */
	public static <T> void writesObj(T[] arr ,File file) throws IOException {
		if(arr == null)
			throw new RuntimeException("写入对象数组为null");
		if(file == null) 
			throw new RuntimeException("文件为null");
		for (T t : arr) 
			writeObj(t,file,true);
	}
	/**
	 * 把一个对象写入到文件
	 * @param <T> 	对象的类型
	 * @param t		该对象
	 * @param file	写入的文件
	 * @throws IOException
	 */
	public static <T> void writeObj(T t ,File file, boolean continuation) throws IOException {
		if(t == null)
			throw new RuntimeException("写入对象为null");
		if(file == null) 
			throw new RuntimeException("文件为null");
		OutputStream out = new FileOutputStream(file);
		MyObjOutStream myoos = new MyObjOutStream(out);
		myoos.writeObject(t);
		myoos.close();
	}
	public static <T> void writeObj(T t ,File file) throws IOException {
		writeObj(t, file, false);
	}
	//4、复制一个文件夹内的所有内容至另一个文件夹中。
	//	(1)	传入的路径必须都是文件夹
	/**
	 * 把一个文件夹拷贝到另一个文件夹
	 * 	里面的文件全部复制过去
	 * @param file1	文件夹1
	 * @param file2	文件夹2
	 */
	public static void copy_dir(File file1,File file2) {   
		if(file1==null || file2==null)
			throw new RuntimeException("文件为null");
		if(!file1.exists())
			throw new RuntimeException("源文件夹不存在");
		if(file1.isFile() || file2.isFile())
			throw new RuntimeException("只能是文件夹");
		if(!file2.exists())//不存在该文件夹，创建该文件夹
			file2.mkdirs();
		//给file2 改名字，如果存在重复名字
		file2 = rename(file1,file2);
		String dir1 = file1.getPath();
		String dir2 = file2.getPath();
		File[] file1s  = file1.listFiles();
		for (File file : file1s) 
			if(file.isDirectory()) 
				copy_dir(dir1+"\\"+file.getName(), dir2+"\\"+file.getName());
			else 
				copy_file(file, file2);
	}
	public static void copy_dir(String dir1,String dir2) {     
		copy_dir(new File(dir1), new File(dir2));
	}
	/**
	 * 任何类型文件的copy
	 * @param file  要复制的文件 file
	 * @param dir  复制到哪里去 dir
	 */
	public static void copy_file(File file, File dir) {
		if(file==null || dir==null)
			throw new RuntimeException("文件或文件夹为null");
		if(!file.exists() || !dir.exists())
			throw new RuntimeException("文件或路径不存在");
		if(file.isDirectory() || dir.isFile())
			throw new RuntimeException("参数1应为文件，参数2应为目录");
		
		dir = rename(file,dir);
		try (
			InputStream in = new FileInputStream(file);
			BufferedInputStream bis = new BufferedInputStream(in);
			OutputStream out = new FileOutputStream(dir);
			BufferedOutputStream bos = new BufferedOutputStream(out);){
			
			byte[] b = new byte[2048];
			int len = 0;
			while((len=bis.read(b))!=-1) {
				bos.write(b,0,len);
				bos.flush();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public static void copy_file(String file, String dir) {
		copy_file(new File(file), new File(dir));
	}

	//2、向一个文件中写入内容。可以选择是否续写。可以指定编码格式
	/**
	 * 以特定编码把字符串写到文件
	 * @param file		写到那个文件
	 * @param str		要写入的字符串
	 * @param continuation 续写吗？
	 * @param encoding	设置编码
	 */
	public static void write(File file, String  str, boolean continuation ,String encoding) {
		if(file == null) 
			throw new RuntimeException("文件为null");
		if(file.isDirectory())
			throw new RuntimeException("只支持文件：" + file.getPath());
		if(str == null)
			throw new RuntimeException("内容不能为null");
		if(encoding == null)
			encoding = "utf-8";
		if(!file.getParentFile().exists()){
			file.getParentFile().mkdirs();
		}
		try (
			OutputStream out = new FileOutputStream(file,continuation);
			OutputStreamWriter osw = new OutputStreamWriter(out,encoding);
			BufferedWriter bw = new BufferedWriter(osw);){
			bw.write(str);
			bw.flush();
			//System.out.println("--写入完成");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	//3、读取一个文档内的所有内容，并返回。可以指定编码格式
	/**
	 * 以特定的编码读取文件
	 * @param file		要读取的文件	
	 * @param encoding	设置编码格式
	 * @return			从文件读到的字符串
	 */
	public static String reade(File file, String encoding) {
		if(file==null)
			throw new RuntimeException("文件为null");
		if(file.isDirectory()) 
			throw new RuntimeException("只支持文件");
		if(!file.exists())
			throw new RuntimeException("文件不存在");
		if(encoding == null)
			encoding = "utf-8";
		
		StringBuilder sb = new StringBuilder();
		try(
			InputStream in = new FileInputStream(file);
			InputStreamReader isr = new InputStreamReader(in, encoding);
			BufferedReader br  = new BufferedReader(isr);){
			
			char[]  c = new char[2048];
			int len = 0;
			while((len=br.read(c)) != -1) 
				sb.append(c,0,len);
			return sb.toString();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return sb.toString();
	}
	public static void write(String file, String  str) {
		write(new File(file), str, false, "utf-8");
	}
	public static void write(File file, String  str) {
		if(!file.getParentFile().exists()){
			file.getParentFile().mkdirs();
		}
		write(file, str, false, "utf-8");
	}
	public static void write(File file, String  str, boolean continuation) {
		write(file, str, continuation, "utf-8");
	}
	public static void write(File file, String  str, String encoding) {
		write(file, str, false, encoding);
	}
	public static String reade(File file) {
		return reade(file, "utf-8");
	}
	public static String reade(String file) {
		return reade(new File(file), "utf-8");
	}
	/**
	 * 从文件读取byte流
	 * @param file	要读byte流的文件
	 * @return		读取的byte流
	 */
	public static byte[] readeByte(File file) {
		return toByteArray(file);
	}
	public static byte[] readeByte(String file) {
		return readeByte(new File(file));
	}
	/**
	 * 从文件读取byte流 --网络方法
	 * @param file	要读byte流的文件
	 * @return		读取的byte流
	 */
	private static byte[] toByteArray(File file) {
		if(file == null)
			throw new RuntimeException("file为null！");
		if(!file.exists())
			throw new RuntimeException("文件不存在");
		if(file.isDirectory())
			throw new RuntimeException("不能使目录");
		File f = file;
		try (
			ByteArrayOutputStream bos = new ByteArrayOutputStream((int) f.length());
			BufferedInputStream in = new BufferedInputStream(new FileInputStream(f));){
			int buf_size = 1024;
			byte[] buffer = new byte[buf_size];
			int len = 0;
			while (-1 != (len = in.read(buffer, 0, buf_size))) 
				bos.write(buffer, 0, len);
			return bos.toByteArray();
		} catch (IOException e) {e.printStackTrace();}
		return null;
	}
	static class MyObjOutStream extends ObjectOutputStream{

		protected MyObjOutStream(OutputStream out) throws IOException, SecurityException {
			super(out);
		}

		protected void writeStreamHeader() {}
	}
	static class MyObjInStream extends ObjectInputStream{


		public MyObjInStream(InputStream in) throws IOException {
			super(in);
		}

		protected void readStreamHeader() {}
	}


}

